package com.alex.httphack.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.HeaderGroup;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alex.common.ILogger;
import com.alex.common.tools.PropertyUtils;
import com.alex.httphack.HackHttpClient;
import com.alex.httphack.HeaderFactory;
import com.alex.httphack.domain.HttpResponseHack;

@Controller
@RequestMapping("/http")
public class HttpController {

	private static final Logger logger = ILogger.logger_common;

	private static final DefaultHttpClient httpClient = new HackHttpClient();
	private static final String COOKIE = "Cookie";
	private static final List<String> httpHeadersList;

	static {
		Field[] fields = HttpHeaders.class.getDeclaredFields();
		httpHeadersList = new ArrayList<String>(fields.length);
		httpHeadersList.add(COOKIE);
		for (Field field : fields) {
			try {
				httpHeadersList.add(field.get(null).toString());
			} catch (Exception e) {
				ILogger.logger_common.error(e.getMessage());
			}
		}
	}

	@RequestMapping(method = { RequestMethod.GET })
	public String index(Model model, HttpServletRequest request)
			throws IllegalArgumentException, IllegalAccessException {
		model.addAttribute("httpHeadersList", httpHeadersList);
		return "http";
	}

	@RequestMapping(value = "post", method = { RequestMethod.GET,
			RequestMethod.POST })
	public @ResponseBody
	String post() throws UnsupportedEncodingException {

		List<NameValuePair> formparams = new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair("param1", "value1"));
		formparams.add(new BasicNameValuePair("param2", "value2"));
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,
				"UTF-8");
		HttpPost httppost = new HttpPost("http://localhost/handler.do");
		httppost.setEntity(entity);

		return null;
	}

	/**
	 * 
	 * @param url
	 * @param headers
	 *            format header=name:value&header=name:value
	 * @param response
	 * @throws IllegalStateException
	 * @throws IOException
	 */
	@RequestMapping(value = "get", method = { RequestMethod.GET,
			RequestMethod.POST })
	public void get(@RequestParam("url") String url,
			@RequestParam("header") String[] headers,
			HttpServletResponse response) throws IllegalStateException,
			IOException {
		if (url.indexOf("/http") != -1 && url.indexOf("/get") != -1
				&& url.indexOf("url") != -1) {
			return;
		}

		HttpGet httpGet = new HttpGet(url);
		HeaderGroup heads = HeaderFactory.newHeaderGroup(headers);
		HeaderFactory.setHeaderGroup(httpGet, heads);
		// mock Host is not allow! e.g. home.jd.com
		// httpGet.setHeader(HttpHeaders.HOST, httpGet.getURI().getHost());

		HttpResponseHack responseHack = null;
		Writer out = null;
		try {
			if (response != null) {
				out = response.getWriter();
			} else {
				out = new PrintWriter(System.out);
			}

			long curt = System.currentTimeMillis();
			HttpContext httpContext = new BasicHttpContext();
			// 使用拦截器
			httpContext.setAttribute("method", httpGet.getMethod());
			responseHack = httpClient.execute(httpGet,
					new ResponseHandler<HttpResponseHack>() {
						@Override
						public HttpResponseHack handleResponse(
								HttpResponse response)
								throws ClientProtocolException, IOException {
							return new HttpResponseHack(response);
						}
					}, httpContext);

			// get charset name
			String servCharsetName = null;
			boolean isForceCharset = false;
			if (response == null && responseHack.getCharset() != null) {
				// java main mode
				servCharsetName = responseHack.getCharset().name();
			} else {
				if (response != null) {
					if (responseHack.getCharset() == null) {
						// like sina.com.cn
						servCharsetName = "GB2312";
						isForceCharset = true;
					} else {
						// using online tomcat's charset, maybe "ISO-8859-1"
						servCharsetName = response.getCharacterEncoding();
					}
				} else {
					// java main mode, is "UTF-8"
					servCharsetName = Charset.defaultCharset().name();
				}
			}

			{
				logger.info("========response headers========");
				logger.info(String
						.format("Using: %s ms, target host: %s, proxy host: %s, using_charset: %s isForceCharset=%s",
								(System.currentTimeMillis() - curt),
								httpContext
										.getAttribute(ExecutionContext.HTTP_TARGET_HOST),
								httpContext
										.getAttribute(ExecutionContext.HTTP_PROXY_HOST),
								servCharsetName, isForceCharset));
				logger.info(HeaderFactory.formatHeaders(responseHack
						.getHeaders()));
			}

			HeaderFactory.copyHeaders(response, responseHack.getHeaders());
			out.write(new String(responseHack.getBody(), servCharsetName));
			out.flush();
		} catch (Exception e) {
			logger.error("", e);
			out.write(e.getMessage() == null ? e.toString() : e.getMessage());
			out.flush();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	public static void main(String[] args) throws Exception {
		HttpController httphack = new HttpController();
		httphack.get("http://www.baidu.com", new String[] {
				"Cookie:" + PropertyUtils.getProperty("baiducookie"),
				"Referer:http://www.sina.com.cn" }, null);
		// http://www.baidu.com/p/kaixinOO1/detail
		// http://order.jd.com/center/list.action?r=635070756725710000

		// httphack.index(null, null);
	}
}
